
#include "stdafx.h"

#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning 
#include <strsafe.h>
#pragma warning( default : 4996 )

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")

#pragma warning (disable : 4995)


#include "../../loader.h"

using namespace dlguif;

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;




// A structure for our custom vertex type
struct CUSTOMVERTEX
{
	FLOAT x, y, z;      // The untransformed, 3D position for the vertex
	DWORD color;        // The vertex color
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)




// 
//LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
//{
//	switch( msg )
//	{
//	case WM_DESTROY:
//		Cleanup();
//		PostQuitMessage( 0 );
//		return 0;
//	}
//
//	return DefWindowProc( hWnd, msg, wParam, lParam );
//}
// 



const int ITEM_TAG_EXIT = 500;
const int ITEM_TAG_ABOUT = 501;



class sample_d3d9_appl
{
public:

	Loader m_loader;
	void* m_window;
	void* m_mainmenu;

	HWND m_hWnd;
 
	LPDIRECT3D9             m_pD3D; 
	LPDIRECT3DDEVICE9       m_device;  
	LPDIRECT3DVERTEXBUFFER9 m_vertexBuffer; 


	sample_d3d9_appl() // : m_loader(L"j:/dlguif/dlguif/delphi_dll_project/dlguif.dll")
	{
		m_loader.SetGuiEventCallBack((FuncGuiEventCallBack)OnGuiEvent, (void*)this );

		m_hWnd = 0;
		m_pD3D = NULL; 
		m_device = NULL;  
		m_vertexBuffer = NULL; 


	}

	~sample_d3d9_appl()
	{

	}

	static void CALLBACK OnGuiEvent(sample_d3d9_appl* appl, const callback_info* ci)
	{
		static int count = 0;
		count ++;

		cout << "form event: " << count << endl;
		cout << "tag: " << ci->tag << endl;
		cout << "type: " << Loader::event_type_to_string(ci->eventType) << endl;
		cout << "Param1: " << ci->param1 <<  endl;
		cout << "Param2: " << ci->param2 <<  endl;
		cout << "Param3: " << ci->param3 <<  endl;
		cout << "Class name: " << ci->class_name << endl;
		cout << "Name: " << ci->name << endl;
		cout << "--------------------------" << endl;

		if(ci->eventType == EVENT_TYPE_MAINMENUITEMCLICK)
		{
			switch(ci->tag)
			{
			case ITEM_TAG_EXIT:
				{
				SendMessageA(appl->m_hWnd, WM_CLOSE, 0, 0);
				}
				break;

			case ITEM_TAG_ABOUT:
				{
				MessageBoxA(appl->m_hWnd, "Sample d3d9 application.", "About ...", 
						MB_OK | MB_ICONINFORMATION | MB_TASKMODAL | MB_TOPMOST);
				}
				break;
			}
		}
	}

	int Init()
	{
		m_window = m_loader.CreateForm("d3d9 render window", "window", 
			&Loader::MakeRectangle(10, 10, 800, 600) );

		m_mainmenu = m_loader.CreateMainMenu(m_window);
		void* temp = NULL;
		temp = m_loader.CreateMainMenuItem(m_mainmenu,NULL, "file");
		temp = m_loader.CreateMainMenuItem(m_mainmenu,"file", "exit");
		m_loader.SetComponentTag(temp, 500);


		temp = m_loader.CreateMainMenuItem(m_mainmenu, NULL,   "help");
		temp = m_loader.CreateMainMenuItem(m_mainmenu, "help", "contents");
		temp = m_loader.CreateMainMenuItem(m_mainmenu, "help", "-");
		temp = m_loader.CreateMainMenuItem(m_mainmenu, "help", "About");
		m_loader.SetComponentTag(temp, ITEM_TAG_ABOUT);

										 


		m_hWnd = m_loader.GetFormWindowHandle(m_window);
		InitD3D( m_hWnd );

		if FAILED(InitGeometry() )
		{
			cerr << "Error init geometry" << endl;
			return -1;
		}

		ShowWindow( m_hWnd, SW_SHOWDEFAULT );
		UpdateWindow( m_hWnd );
 
		return 0;
	}


	HRESULT InitD3D( HWND hWnd )
	{
		// Create the D3D object.
		if( NULL == ( m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
			return E_FAIL;

		// Set up the structure used to create the D3DDevice
		D3DPRESENT_PARAMETERS d3dpp;
		ZeroMemory( &d3dpp, sizeof( d3dpp ) );
		d3dpp.Windowed = TRUE;
		d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
		d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

		// Create the D3DDevice
		if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
			D3DCREATE_SOFTWARE_VERTEXPROCESSING,
			&d3dpp, &m_device ) ) )
		{
			return E_FAIL;
		}

		// Turn off culling, so we see the front and back of the triangle
		m_device->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

		// Turn off D3D lighting, since we are providing our own vertex colors
		m_device->SetRenderState( D3DRS_LIGHTING, FALSE );

		return S_OK;
	}




	HRESULT InitGeometry()
	{
		// Initialize three vertices for rendering a triangle
		CUSTOMVERTEX g_Vertices[] =
		{
			{ -1.0f,-1.0f, 0.0f, 0xffff0000, },
			{  1.0f,-1.0f, 0.0f, 0xff0000ff, },
			{  0.0f, 1.0f, 0.0f, 0xffffffff, },
		};

		// Create the vertex buffer.
		if( FAILED( m_device->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),
			0, D3DFVF_CUSTOMVERTEX,
			D3DPOOL_DEFAULT, &m_vertexBuffer, NULL ) ) )
		{
			return E_FAIL;
		}

		// Fill the vertex buffer.
		VOID* pVertices;
		if( FAILED( m_vertexBuffer->Lock( 0, sizeof( g_Vertices ), ( void** )&pVertices, 0 ) ) )
			return E_FAIL;
		memcpy( pVertices, g_Vertices, sizeof( g_Vertices ) );
		m_vertexBuffer->Unlock();

		return S_OK;
	}



	void Run()
	{

		MSG msg;
		memset( &msg, 0, sizeof( msg ) );
		while( msg.message != WM_QUIT )
		{
			if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
			{
				TranslateMessage( &msg );
				DispatchMessage( &msg );
			}
			else
				Render();
		}


	}


	VOID Render()
	{
		// Clear the backbuffer to a black color
		m_device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );

		// Begin the scene
		if( SUCCEEDED( m_device->BeginScene() ) )
		{
			// Setup the world, view, and projection matrices
			SetupMatrices();

			// Render the vertex buffer contents
			m_device->SetStreamSource( 0, m_vertexBuffer, 0, sizeof( CUSTOMVERTEX ) );
			m_device->SetFVF( D3DFVF_CUSTOMVERTEX );
			m_device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );

			// End the scene
			m_device->EndScene();
		}

		// Present the backbuffer contents to the display
		m_device->Present( NULL, NULL, NULL, NULL );
	}

	VOID Cleanup()
	{
		if( m_vertexBuffer != NULL )
			m_vertexBuffer->Release();

		if( m_device != NULL )
			m_device->Release();

		if( m_pD3D != NULL )
			m_pD3D->Release();
	}


	VOID SetupMatrices()
	{

		D3DXMATRIXA16 matWorld;
 
		float fAngle = 4.0f * 0.001f * (float)timeGetTime();
		D3DXMatrixRotationY( &matWorld, fAngle );
		m_device->SetTransform( D3DTS_WORLD, &matWorld );

		// Set up our view matrix. A view matrix can be defined given an eye point,
		// a point to lookat, and a direction for which way is up. Here, we set the
		// eye five units back along the z-axis and up three units, look at the
		// origin, and define "up" to be in the y-direction.
		D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
		D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
		D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
		D3DXMATRIXA16 matView;
		D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
		m_device->SetTransform( D3DTS_VIEW, &matView );

		// For the projection matrix, we set up a perspective transform (which
		// transforms geometry from 3D view space to 2D viewport space, with
		// a perspective divide making objects smaller in the distance). To build
		// a perpsective transform, we need the field of view (1/4 pi is common),
		// the aspect ratio, and the near and far clipping planes (which define at
		// what distances geometry should be no longer be rendered).
		D3DXMATRIXA16 matProj;
		D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
		m_device->SetTransform( D3DTS_PROJECTION, &matProj );
	}




};


// 
//INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
//{
//	UNREFERENCED_PARAMETER( hInst );
//
//	// Register the window class
//	WNDCLASSEX wc =
//	{
//		sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
//		GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
//		L"D3D Tutorial", NULL
//	};
//	RegisterClassEx( &wc );
//
//	// Create the application's window
//	HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 03: Matrices",
//		WS_OVERLAPPEDWINDOW, 100, 100, 256, 256,
//		NULL, NULL, wc.hInstance, NULL );
//
//	// Initialize Direct3D
//	if( SUCCEEDED( InitD3D( hWnd ) ) )
//	{
//		// Create the scene geometry
//		if( SUCCEEDED( InitGeometry() ) )
//		{
//			// Show the window
//			ShowWindow( hWnd, SW_SHOWDEFAULT );
//			UpdateWindow( hWnd );
//
//			// Enter the message loop
//			MSG msg;
//			ZeroMemory( &msg, sizeof( msg ) );
//			while( msg.message != WM_QUIT )
//			{
//				if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
//				{
//					TranslateMessage( &msg );
//					DispatchMessage( &msg );
//				}
//				else
//					Render();
//			}
//		}
//	}
//
//	UnregisterClass( L"D3D Tutorial", wc.hInstance );
//	return 0;
//}
// 


int _tmain(int argc, _TCHAR* argv[])
{

	sample_d3d9_appl appl;
	appl.Init();
	appl.Run();

	return 0;
}


